#include <asm/asm_macros_common.S>
#include <asm/uart.h>

    .global uart_init
    .global uart_putc
    .global uart_puts
    .global uart_getc
    .global print_u32
    .global mdelay
    .global udelay
    .global uart_flush_data
    .global print_u64

	/* -----------------------------------------------
	 * int uart_init(unsigned int uart_clk, unsigned int baud_rate)
	 * Function to initialize the console without a C Runtime to 
     * print debug information.
	 * In: a0 - Uart clock in Hz
	 *     a1 - Baud rate
	 * Out: return 1 on success, 0 on error
	 * -----------------------------------------------
	 */
func uart_init
    beqz a0, init_fail
    beqz a1, init_fail

    li t0, UART_BASE
    /*disable uart interrupt*/
    addi t1, zero, 0
    sw t1, UART_IER(t0)

    slli a1, a1, 4
    divu a1, a0, a1
    and a0, a1, 0xff  /* a0 = UART DLL */
    srli a1, a1, 8
    and a1, a1, 0xff /* a1 = UART DLH */

    addi t1, zero, 0x80
    sw t1, UART_LCR(t0)
    sw a0, UART_DLL(t0)
    sw a1, UART_DLH(t0)

    addi t1, zero, 3
    sw t1, UART_LCR(t0)

    addi a0, zero, 0
    ret
init_fail:
    addi a0, zero, 1
    ret
endfunc uart_init

	/* -----------------------------------------------
	 * void uart_putc(unsigned char ch)
	 * Function to print character 
	 * In: a0 - ascii character
	 * Out: none
	 * -----------------------------------------------
	 */
func uart_putc
    li t0, UART_BASE

    sw a0, UART_THR(t0)
.L2:
    lw t1, UART_LSR(t0)
    andi t1, t1, 0x40
    beqz t1, .L2
    ret
endfunc uart_putc

    /* -----------------------------------------------
	 * void uart_puts(unsigned char *str)
	 * Function to print strings. 
	 * In: a0 - the address of strings.
	 * Out: none
	 * -----------------------------------------------
	 */
func uart_puts
    addi  sp, sp, -24
    sd ra, 16(sp)

    mv a5, a0
.L3:
    lbu a0, (a5)
    beqz a0, .L4
    call uart_putc
    addi a5, a5, 1
    j .L3

.L4:
    ld ra, 16(sp)
	addi sp, sp, 24
    ret
endfunc uart_puts

    /* -----------------------------------------------
	 * int uart_getc(unsigned char *ch, uint64_t timeout_ms)
	 * Function to get  character from uart
	 * In: a0: timeout
	 * Out: a0: 0 fail
     *          1 success
	 * -----------------------------------------------
	 */
func uart_getc
    li t0, UART_BASE
    li t3, MDELAY_TICKS
    mul t3, t3, a1
    rdtime a1
    add t3, t3, a1

.L5:
    rdtime a1
    bltu t3, a1, getc_fail
    lw t1, UART_LSR(t0)
    and t1, t1, 1
    beqz t1, .L5

    lw a1, UART_RBR(t0)
    and a1, a1, 0xff
    sb a1, 0(a0)
    addi a0, zero, 1
    ret
getc_fail:
    addi a0, zero, 0
    ret
endfunc uart_getc

func uart_flush_data
    addi sp, sp, -24
    sd ra, 16(sp)   /*调用call ,需要保存ra寄存器*/
    
flush_L1:
    addi a0, sp, 8   /* &ch */
    li a1, 10   /*10ms*/
    call uart_getc    
    bnez a0, flush_L1

    ld ra, 16(sp)
    addi sp, sp, 24
	ret
endfunc uart_flush_data


func print_u32
    addi sp, sp, -48
	sd ra, 40(sp)
	sw a0, 12(sp)
	addi a3, sp, 16

	li a5, 8
	li a6, 9
print_L1:
	addiw a2, a5, -1
	srliw a4, a2, 1
	addi a4, a4, 32
	add	a4, a4, sp
	lbu	a1, -20(a4)
	andi a0, a5, 1
	mv a5, a2
	srli a4, a1, 4
	beqz a0, print_L2
	andi a4, a1, 0xf

print_L2:
	addi a2, a4, 55  /* 'A' - 10*/
	bltu a6, a4, print_L3 
	addi a2, a4, 48 /* '0' */

print_L3:
	sb a2, 0(a3)
	addi a3, a3, 1
	bnez a5, print_L1
   
	addi a0, sp, 16
	sb zero, 24(sp)   /* add '\0' */
	jal	ra, uart_puts 

	ld ra, 40(sp)
	addi sp, sp, 48
	ret
endfunc print_u32

func print_u64
    addi	sp,sp,-64
	sd	ra,56(sp)
	sd	a0,8(sp)
	addi	a3,sp,24

	li	a5,16
	li	a6,9
print64_L1:
	addiw	a2,a5,-1
	sraiw	a4,a2,0x1
	addi	a4,a4,48
	add	a4,a4,sp
	lbu	a1,-40(a4)
	andi	a0,a5,1
	mv	a5,a2
	srli	a4,a1,0x4
	beqz	a0,print64_L2 
	andi	a4,a1,15
           
print64_L2:
	addi	a2,a4,55
	bltu	a6,a4,print64_L3
	addi	a2,a4,48
        
print64_L3:
	sb	a2,0(a3)
	addi	a3,a3,1
	bnez	a5,print64_L1

	addi	a0,sp,24
	sb	zero,40(sp)
	jal	ra,uart_puts 

	ld	ra,56(sp)
	addi	sp,sp,64
	ret
endfunc print_u64

    /* -----------------------------------------------
	 * void mdelay(ulong ms)
	 * Function to delay ms
	 * In: a0: ms
	 * Out: None
	 * -----------------------------------------------
	 */
func mdelay
    li t0, MDELAY_TICKS
    mul a0, a0, t0
    rdtime a1
    add a0, a0, a1
mdelay_L1:
    rdtime a1
    bltu a1, a0, mdelay_L1
    ret
endfunc mdelay

    /* -----------------------------------------------
	 * void mdelay(ulong us)
	 * Function to delay us
	 * In: a0: us
	 * Out: None
	 * -----------------------------------------------
	 */
func udelay
    li t0, UDELAY_TICKS
    mul a0, a0, t0
    rdtime a1
    add a0, a0, a1
udelay_L1:
    rdtime a1
    bltu a1, a0, udelay_L1
    ret
endfunc udelay


